"""
权限管理器

负责权限的授予、撤销、检查等操作
"""

import sys
import os
from typing import List, Dict, Any, Optional
from datetime import datetime

# 添加路径
current_dir = os.path.dirname(os.path.abspath(__file__))
parent_dir = os.path.dirname(current_dir)
operating_system_dir = os.path.join(parent_dir, "OperatingSystem")
if operating_system_dir not in sys.path:
    sys.path.insert(0, operating_system_dir)

from privilege_types import (
    PrivilegeType, ResourceType, PrivilegeInfo, PermissionResult, 
    UserInfo, get_required_privilege, PREDEFINED_ROLES
)
from system_schema import SYSTEM_DATABASE_NAME


class PermissionManager:
    """权限管理器"""
    
    def __init__(self, database_manager):
        """
        初始化权限管理器
        
        Args:
            database_manager: 数据库管理器实例
        """
        self.database_manager = database_manager
        self.system_db = None  # 系统数据库实例
        self.privileges_cache = {}  # 权限缓存 {user_key: {resource_key: [PrivilegeInfo]}}
        self.roles_cache = {}  # 角色缓存 {role_name: RoleInfo}
        
        # 获取系统数据库实例
        self._initialize_system_database()
        
        # 加载权限信息到缓存
        self._load_privileges_cache()
    
    def _initialize_system_database(self):
        """初始化系统数据库"""
        try:
            self.system_db = self.database_manager.get_database(SYSTEM_DATABASE_NAME)
            if not self.system_db:
                raise RuntimeError(f"System database '{SYSTEM_DATABASE_NAME}' not found")
        except Exception as e:
            raise RuntimeError(f"Failed to initialize system database: {e}")
    
    def _load_privileges_cache(self):
        """从系统表加载权限信息到缓存"""
        try:
            self.privileges_cache = {}
            
            # 加载全局权限
            self._load_global_privileges()
            
            # 加载数据库权限
            self._load_database_privileges()
            
            # 加载表权限
            self._load_table_privileges()
            
            # 加载列权限
            self._load_column_privileges()
            
            # 加载角色信息
            self._load_roles_cache()
            
        except Exception as e:
            print(f"Warning: Failed to load privileges cache: {e}")
            self.privileges_cache = {}
    
    def _load_global_privileges(self):
        """加载全局权限"""
        try:
            records = self.system_db.select_records("global_privs")
            
            for record in records:
                user_key = f"{record['username']}@{record['host']}"
                privilege_info = PrivilegeInfo(
                    privilege_type=PrivilegeType(record['privilege_type']),
                    resource_type=ResourceType.GLOBAL,
                    resource_name="*",
                    is_grantable=record['is_grantable'],
                    granted_time=datetime.fromisoformat(record['granted_time']) if isinstance(record['granted_time'], str) else record['granted_time'],
                    granted_by=record.get('granted_by')
                )
                
                self._add_privilege_to_cache(user_key, "GLOBAL:*", privilege_info)
                
        except Exception as e:
            print(f"Warning: Failed to load global privileges: {e}")
    
    def _load_database_privileges(self):
        """加载数据库权限"""
        try:
            records = self.system_db.select_records("db_privs")
            
            for record in records:
                user_key = f"{record['username']}@{record['host']}"
                resource_key = f"DATABASE:{record['db_name']}"
                privilege_info = PrivilegeInfo(
                    privilege_type=PrivilegeType(record['privilege_type']),
                    resource_type=ResourceType.DATABASE,
                    resource_name=record['db_name'],
                    is_grantable=record['is_grantable'],
                    granted_time=datetime.fromisoformat(record['granted_time']) if isinstance(record['granted_time'], str) else record['granted_time'],
                    granted_by=record.get('granted_by')
                )
                
                self._add_privilege_to_cache(user_key, resource_key, privilege_info)
                
        except Exception as e:
            print(f"Warning: Failed to load database privileges: {e}")
    
    def _load_table_privileges(self):
        """加载表权限"""
        try:
            records = self.system_db.select_records("table_privs")
            
            for record in records:
                user_key = f"{record['username']}@{record['host']}"
                resource_key = f"TABLE:{record['db_name']}.{record['table_name']}"
                privilege_info = PrivilegeInfo(
                    privilege_type=PrivilegeType(record['privilege_type']),
                    resource_type=ResourceType.TABLE,
                    resource_name=f"{record['db_name']}.{record['table_name']}",
                    is_grantable=record['is_grantable'],
                    granted_time=datetime.fromisoformat(record['granted_time']) if isinstance(record['granted_time'], str) else record['granted_time'],
                    granted_by=record.get('granted_by')
                )
                
                self._add_privilege_to_cache(user_key, resource_key, privilege_info)
                
        except Exception as e:
            print(f"Warning: Failed to load table privileges: {e}")
    
    def _load_column_privileges(self):
        """加载列权限"""
        try:
            records = self.system_db.select_records("column_privs")
            
            for record in records:
                user_key = f"{record['username']}@{record['host']}"
                resource_key = f"COLUMN:{record['db_name']}.{record['table_name']}.{record['column_name']}"
                privilege_info = PrivilegeInfo(
                    privilege_type=PrivilegeType(record['privilege_type']),
                    resource_type=ResourceType.COLUMN,
                    resource_name=f"{record['db_name']}.{record['table_name']}.{record['column_name']}",
                    is_grantable=record['is_grantable'],
                    granted_time=datetime.fromisoformat(record['granted_time']) if isinstance(record['granted_time'], str) else record['granted_time'],
                    granted_by=record.get('granted_by')
                )
                
                self._add_privilege_to_cache(user_key, resource_key, privilege_info)
                
        except Exception as e:
            print(f"Warning: Failed to load column privileges: {e}")
    
    def _load_roles_cache(self):
        """加载角色缓存"""
        try:
            # 加载预定义角色
            self.roles_cache = PREDEFINED_ROLES.copy()
            
            # 从数据库加载自定义角色
            roles_records = self.system_db.select_records("roles")
            role_privs_records = self.system_db.select_records("role_privs")
            
            # 构建角色权限映射
            role_privileges = {}
            for record in role_privs_records:
                role_name = record['role_name']
                if role_name not in role_privileges:
                    role_privileges[role_name] = []
                
                privilege_info = PrivilegeInfo(
                    privilege_type=PrivilegeType(record['privilege_type']),
                    resource_type=ResourceType(record['resource_type']),
                    resource_name=record['resource_name'],
                    is_grantable=record['is_grantable'],
                    granted_time=datetime.fromisoformat(record['granted_time']) if isinstance(record['granted_time'], str) else record['granted_time']
                )
                role_privileges[role_name].append(privilege_info)
            
        except Exception as e:
            print(f"Warning: Failed to load roles cache: {e}")
    
    def _add_privilege_to_cache(self, user_key: str, resource_key: str, privilege_info: PrivilegeInfo):
        """添加权限到缓存"""
        if user_key not in self.privileges_cache:
            self.privileges_cache[user_key] = {}
        
        if resource_key not in self.privileges_cache[user_key]:
            self.privileges_cache[user_key][resource_key] = []
        
        self.privileges_cache[user_key][resource_key].append(privilege_info)
    
    def grant_privilege(self, privilege_type: PrivilegeType, resource_type: ResourceType,
                       resource_name: str, target_username: str, target_host: str = '%',
                       is_grantable: bool = False, granted_by: str = 'system') -> bool:
        """
        授予权限
        
        Args:
            privilege_type: 权限类型
            resource_type: 资源类型
            resource_name: 资源名称
            target_username: 目标用户名
            target_host: 目标主机
            is_grantable: 是否可授权
            granted_by: 授权者
            
        Returns:
            bool: 授权是否成功
        """
        try:
            # 检查权限是否已存在
            if self._has_privilege(target_username, target_host, privilege_type, resource_type, resource_name):
                return True  # 权限已存在
            
            # 准备记录数据
            grant_time = datetime.now()
            base_record = {
                "username": target_username,
                "host": target_host,
                "privilege_type": privilege_type.value,
                "is_grantable": is_grantable,
                "granted_time": grant_time,
                "granted_by": granted_by
            }
            
            # 根据资源类型插入到相应表
            if resource_type == ResourceType.GLOBAL:
                success = self.system_db.insert_record("global_privs", base_record)
                
            elif resource_type == ResourceType.DATABASE:
                record = {**base_record, "db_name": resource_name}
                success = self.system_db.insert_record("db_privs", record)
                
            elif resource_type == ResourceType.TABLE:
                db_name, table_name = resource_name.split('.', 1)
                record = {**base_record, "db_name": db_name, "table_name": table_name}
                success = self.system_db.insert_record("table_privs", record)
                
            elif resource_type == ResourceType.COLUMN:
                parts = resource_name.split('.')
                if len(parts) != 3:
                    raise ValueError(f"Invalid column resource name: {resource_name}")
                db_name, table_name, column_name = parts
                record = {**base_record, "db_name": db_name, "table_name": table_name, "column_name": column_name}
                success = self.system_db.insert_record("column_privs", record)
            else:
                raise ValueError(f"Unsupported resource type: {resource_type}")
            
            if success:
                # 更新缓存
                user_key = f"{target_username}@{target_host}"
                resource_key = f"{resource_type.value}:{resource_name}"
                privilege_info = PrivilegeInfo(
                    privilege_type=privilege_type,
                    resource_type=resource_type,
                    resource_name=resource_name,
                    is_grantable=is_grantable,
                    granted_time=grant_time,
                    granted_by=granted_by
                )
                self._add_privilege_to_cache(user_key, resource_key, privilege_info)
                
                return True
            
            return False
            
        except Exception as e:
            print(f"Error granting privilege {privilege_type.value} on {resource_type.value} {resource_name} to {target_username}@{target_host}: {e}")
            return False
    
    def revoke_privilege(self, privilege_type: PrivilegeType, resource_type: ResourceType,
                        resource_name: str, target_username: str, target_host: str = '%') -> bool:
        """
        撤销权限
        
        Args:
            privilege_type: 权限类型
            resource_type: 资源类型
            resource_name: 资源名称
            target_username: 目标用户名
            target_host: 目标主机
            
        Returns:
            bool: 撤销是否成功
        """
        try:
            base_condition = {
                "username": target_username,
                "host": target_host,
                "privilege_type": privilege_type.value
            }
            
            # 根据资源类型从相应表删除
            if resource_type == ResourceType.GLOBAL:
                deleted_count = self.system_db.delete_records("global_privs", base_condition)
                
            elif resource_type == ResourceType.DATABASE:
                condition = {**base_condition, "db_name": resource_name}
                deleted_count = self.system_db.delete_records("db_privs", condition)
                
            elif resource_type == ResourceType.TABLE:
                db_name, table_name = resource_name.split('.', 1)
                condition = {**base_condition, "db_name": db_name, "table_name": table_name}
                deleted_count = self.system_db.delete_records("table_privs", condition)
                
            elif resource_type == ResourceType.COLUMN:
                parts = resource_name.split('.')
                if len(parts) != 3:
                    raise ValueError(f"Invalid column resource name: {resource_name}")
                db_name, table_name, column_name = parts
                condition = {**base_condition, "db_name": db_name, "table_name": table_name, "column_name": column_name}
                deleted_count = self.system_db.delete_records("column_privs", condition)
            else:
                raise ValueError(f"Unsupported resource type: {resource_type}")
            
            if deleted_count > 0:
                # 更新缓存
                self._remove_privilege_from_cache(target_username, target_host, privilege_type, resource_type, resource_name)
                return True
            
            return False
            
        except Exception as e:
            print(f"Error revoking privilege {privilege_type.value} on {resource_type.value} {resource_name} from {target_username}@{target_host}: {e}")
            return False
    
    def check_privilege(self, user_info: UserInfo, privilege_type: PrivilegeType,
                       resource_type: ResourceType, resource_name: str) -> PermissionResult:
        """
        检查用户权限
        
        Args:
            user_info: 用户信息
            privilege_type: 权限类型
            resource_type: 资源类型
            resource_name: 资源名称
            
        Returns:
            PermissionResult: 权限检查结果
        """
        try:
            user_key = user_info.get_user_key()
            
            # 1. 检查直接权限
            direct_result = self._check_direct_privilege(user_key, privilege_type, resource_type, resource_name)
            if direct_result.allowed:
                return direct_result
            
            # 2. 检查角色权限
            role_result = self._check_role_privilege(user_key, privilege_type, resource_type, resource_name)
            if role_result.allowed:
                return role_result
            
            # 3. 检查通配符权限
            wildcard_result = self._check_wildcard_privilege(user_key, privilege_type, resource_type, resource_name)
            if wildcard_result.allowed:
                return wildcard_result
            
            # 4. 检查ALL_PRIVILEGES权限
            all_privileges_result = self._check_all_privileges(user_key, resource_type, resource_name)
            if all_privileges_result.allowed:
                return all_privileges_result
            
            # 权限检查失败
            return PermissionResult(
                allowed=False,
                reason=f"Access denied: {privilege_type.value} privilege required",
                audit_info={
                    "user": user_key,
                    "privilege": privilege_type.value,
                    "resource": f"{resource_type.value}:{resource_name}"
                }
            )
            
        except Exception as e:
            return PermissionResult(
                allowed=False,
                reason=f"Permission check error: {e}",
                audit_info={"error": str(e)}
            )
    
    def check_operation_privilege(self, user_info: UserInfo, operation: str, 
                                 database_name: str = None, table_name: str = None) -> PermissionResult:
        """
        检查操作权限
        
        Args:
            user_info: 用户信息
            operation: 操作类型
            database_name: 数据库名称
            table_name: 表名称
            
        Returns:
            PermissionResult: 权限检查结果
        """
        try:
            # 获取操作所需权限
            required_privilege = get_required_privilege(operation)
            
            # 确定资源类型和名称
            if table_name and database_name:
                resource_type = ResourceType.TABLE
                resource_name = f"{database_name}.{table_name}"
            elif database_name:
                resource_type = ResourceType.DATABASE
                resource_name = database_name
            else:
                resource_type = ResourceType.GLOBAL
                resource_name = "*"
            
            return self.check_privilege(user_info, required_privilege, resource_type, resource_name)
            
        except Exception as e:
            return PermissionResult(
                allowed=False,
                reason=f"Operation privilege check error: {e}",
                audit_info={"operation": operation, "error": str(e)}
            )
    
    def get_user_privileges(self, username: str, host: str = '%') -> List[PrivilegeInfo]:
        """
        获取用户的所有权限
        
        Args:
            username: 用户名
            host: 主机
            
        Returns:
            List[PrivilegeInfo]: 权限列表
        """
        user_key = f"{username}@{host}"
        all_privileges = []
        
        # 获取直接权限
        if user_key in self.privileges_cache:
            for resource_privileges in self.privileges_cache[user_key].values():
                all_privileges.extend(resource_privileges)
        
        # 获取角色权限
        role_privileges = self._get_user_role_privileges(username, host)
        all_privileges.extend(role_privileges)
        
        return all_privileges
    
    def get_accessible_databases(self, user_info: UserInfo, all_databases: List[str]) -> List[str]:
        """
        获取用户可访问的数据库列表
        
        Args:
            user_info: 用户信息
            all_databases: 所有数据库列表
            
        Returns:
            List[str]: 用户可访问的数据库列表
        """
        accessible_databases = []
        
        for db_name in all_databases:
            # 检查用户是否有任意权限访问该数据库
            result = self.check_privilege(user_info, PrivilegeType.USAGE, ResourceType.DATABASE, db_name)
            if result.allowed:
                accessible_databases.append(db_name)
            else:
                # 检查是否有任何表级权限
                for privilege_type in [PrivilegeType.SELECT, PrivilegeType.INSERT, PrivilegeType.UPDATE, PrivilegeType.DELETE]:
                    result = self.check_privilege(user_info, privilege_type, ResourceType.DATABASE, db_name)
                    if result.allowed:
                        accessible_databases.append(db_name)
                        break
        
        return accessible_databases
    
    def _check_direct_privilege(self, user_key: str, privilege_type: PrivilegeType,
                               resource_type: ResourceType, resource_name: str) -> PermissionResult:
        """检查直接权限"""
        if user_key not in self.privileges_cache:
            return PermissionResult(allowed=False, reason="No privileges found")
        
        user_privileges = self.privileges_cache[user_key]
        resource_key = f"{resource_type.value}:{resource_name}"
        
        if resource_key in user_privileges:
            for privilege_info in user_privileges[resource_key]:
                if privilege_info.privilege_type == privilege_type:
                    return PermissionResult(
                        allowed=True,
                        reason="Direct privilege match",
                        privilege_source="direct"
                    )
        
        return PermissionResult(allowed=False, reason="No direct privilege match")
    
    def _check_role_privilege(self, user_key: str, privilege_type: PrivilegeType,
                             resource_type: ResourceType, resource_name: str) -> PermissionResult:
        """检查角色权限"""
        # 获取用户角色
        user_roles = self._get_user_roles(user_key)
        
        for role_name in user_roles:
            if role_name in self.roles_cache:
                role_info = self.roles_cache[role_name]
                for privilege_info in role_info.privileges:
                    if (privilege_info.privilege_type == privilege_type and
                        privilege_info.matches_resource(resource_type, resource_name)):
                        return PermissionResult(
                            allowed=True,
                            reason=f"Role privilege match: {role_name}",
                            privilege_source=f"role:{role_name}"
                        )
        
        return PermissionResult(allowed=False, reason="No role privilege match")
    
    def _check_wildcard_privilege(self, user_key: str, privilege_type: PrivilegeType,
                                 resource_type: ResourceType, resource_name: str) -> PermissionResult:
        """检查通配符权限"""
        if user_key not in self.privileges_cache:
            return PermissionResult(allowed=False, reason="No privileges found")
        
        user_privileges = self.privileges_cache[user_key]
        
        # 检查全局通配符权限
        global_key = "GLOBAL:*"
        if global_key in user_privileges:
            for privilege_info in user_privileges[global_key]:
                if privilege_info.privilege_type == privilege_type:
                    return PermissionResult(
                        allowed=True,
                        reason="Global wildcard privilege match",
                        privilege_source="wildcard"
                    )
        
        # 检查数据库通配符权限（如果是表级资源）
        if resource_type == ResourceType.TABLE and '.' in resource_name:
            db_name = resource_name.split('.')[0]
            db_key = f"DATABASE:{db_name}"
            if db_key in user_privileges:
                for privilege_info in user_privileges[db_key]:
                    if privilege_info.privilege_type == privilege_type:
                        return PermissionResult(
                            allowed=True,
                            reason="Database wildcard privilege match",
                            privilege_source="wildcard"
                        )
        
        return PermissionResult(allowed=False, reason="No wildcard privilege match")
    
    def _check_all_privileges(self, user_key: str, resource_type: ResourceType, resource_name: str) -> PermissionResult:
        """检查ALL_PRIVILEGES权限"""
        if user_key not in self.privileges_cache:
            return PermissionResult(allowed=False, reason="No privileges found")
        
        user_privileges = self.privileges_cache[user_key]
        
        # 检查全局ALL_PRIVILEGES
        global_key = "GLOBAL:*"
        if global_key in user_privileges:
            for privilege_info in user_privileges[global_key]:
                if privilege_info.privilege_type == PrivilegeType.ALL_PRIVILEGES:
                    return PermissionResult(
                        allowed=True,
                        reason="ALL_PRIVILEGES match",
                        privilege_source="all_privileges"
                    )
        
        return PermissionResult(allowed=False, reason="No ALL_PRIVILEGES match")
    
    def _has_privilege(self, username: str, host: str, privilege_type: PrivilegeType,
                      resource_type: ResourceType, resource_name: str) -> bool:
        """检查权限是否已存在"""
        user_key = f"{username}@{host}"
        resource_key = f"{resource_type.value}:{resource_name}"
        
        if user_key not in self.privileges_cache:
            return False
        
        if resource_key not in self.privileges_cache[user_key]:
            return False
        
        for privilege_info in self.privileges_cache[user_key][resource_key]:
            if privilege_info.privilege_type == privilege_type:
                return True
        
        return False
    
    def _remove_privilege_from_cache(self, username: str, host: str, privilege_type: PrivilegeType,
                                   resource_type: ResourceType, resource_name: str):
        """从缓存中移除权限"""
        user_key = f"{username}@{host}"
        resource_key = f"{resource_type.value}:{resource_name}"
        
        if user_key not in self.privileges_cache:
            return
        
        if resource_key not in self.privileges_cache[user_key]:
            return
        
        # 移除匹配的权限
        self.privileges_cache[user_key][resource_key] = [
            p for p in self.privileges_cache[user_key][resource_key]
            if p.privilege_type != privilege_type
        ]
        
        # 如果资源下没有权限了，删除资源键
        if not self.privileges_cache[user_key][resource_key]:
            del self.privileges_cache[user_key][resource_key]
    
    def _get_user_roles(self, user_key: str) -> List[str]:
        """获取用户角色列表"""
        # 简化实现：从数据库查询用户角色
        try:
            username, host = user_key.split('@', 1)
            condition = {"username": username, "host": host}
            records = self.system_db.select_records("user_roles", condition)
            return [record["role_name"] for record in records]
        except Exception:
            return []
    
    def _get_user_role_privileges(self, username: str, host: str) -> List[PrivilegeInfo]:
        """获取用户的角色权限"""
        user_key = f"{username}@{host}"
        user_roles = self._get_user_roles(user_key)
        role_privileges = []
        
        for role_name in user_roles:
            if role_name in self.roles_cache:
                role_info = self.roles_cache[role_name]
                role_privileges.extend(role_info.privileges)
        
        return role_privileges
    
    def create_default_root_privileges(self) -> bool:
        """为root用户创建默认权限"""
        try:
            # 授予root用户ALL_PRIVILEGES权限
            success = self.grant_privilege(
                privilege_type=PrivilegeType.ALL_PRIVILEGES,
                resource_type=ResourceType.GLOBAL,
                resource_name="*",
                target_username="root",
                target_host="%",
                is_grantable=True,
                granted_by="system"
            )
            
            if success:
                print("Granted ALL_PRIVILEGES to root user")
            
            return success
            
        except Exception as e:
            print(f"Error creating default root privileges: {e}")
            return False
